package mspbots.cw.client.core;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.log4j.Log4j2;
import mspbots.cw.client.core.client.ClientProperties;
import mspbots.cw.client.core.client.CwWebClient;
import mspbots.cw.common.RabbitKeys;
import mspbots.cw.common.RedisKeys;
import mspbots.cw.common.ResultMsg;
import org.springframework.amqp.rabbit.core.RabbitMessagingTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.ReactiveRedisTemplate;
import org.springframework.data.redis.core.ReactiveStringRedisTemplate;
import org.springframework.http.HttpStatus;
import reactor.core.publisher.Mono;

import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * @author billb
 */
@Log4j2
public abstract class AbstractToolsUtil {

    protected ObjectMapper objectMapper;

    protected CwWebClient cwWebClient;

    protected RabbitMessagingTemplate messagingTemplate;
    protected ReactiveStringRedisTemplate stringRedisTemplate;
    protected ReactiveRedisTemplate<String, Object> reactiveRedisTemplate;

    private RabbitMessagingTemplate rabbitMessagingTemplate;

    protected Mono<ClientProperties> loadProperties(Long tenantId) {
        return this.reactiveRedisTemplate.opsForValue()
                .get(RedisKeys.TENANT_PROPERTIES_REDIS_KEY_PREFIX + tenantId)
                .switchIfEmpty(Mono.error(new mspbots.cw.common.annotation.ApiException(HttpStatus.NOT_FOUND,
                        "This tenant id [" + tenantId + "] client properties is empty.")))
                .map(data -> this.objectMapper.convertValue(data, ClientProperties.class));
    }

    /**
     * default sync all config data, such as "user","team","board"
     */
    protected Mono<LocalDateTime> readAnchorTimeLong(String key) {
        return this.stringRedisTemplate.opsForValue().get(key)
                .map(LocalDateTime::parse)
                .defaultIfEmpty(LocalDateTime.now().minusYears(20));
    }

    /**
     * default sync all business data, such as "ticket","timeEntry"
     */
    protected Mono<LocalDateTime> readAnchorTime(String key) {
        return this.stringRedisTemplate.opsForValue().get(key)
                .map(LocalDateTime::parse)
                .defaultIfEmpty(LocalDateTime.now().minusYears(20));
    }

    protected void recordAnchorTime(String key, String value) {
        LocalDateTime nowAnchorTime = LocalDateTime.parse(value, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
        this.readAnchorTime(key)
                .filter(v -> v.isBefore(nowAnchorTime))
                .flatMap(v -> this.stringRedisTemplate.opsForValue()
                        .set(key, nowAnchorTime.format(DateTimeFormatter.ISO_DATE_TIME), Duration.ofDays(30)))
                .subscribe();
    }

    protected void recordAnchorTimeLong(String key, String value) {
        LocalDateTime nowAnchorTime = LocalDateTime.parse(value, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
        this.readAnchorTimeLong(key)
                .filter(v -> v.isBefore(nowAnchorTime))
                .flatMap(v -> this.stringRedisTemplate.opsForValue()
                        .set(key, nowAnchorTime.format(DateTimeFormatter.ISO_DATE_TIME), Duration.ofDays(30)))
                .subscribe();
    }

    protected void sendEntity(String key, ResultMsg resultMsg) {
        this.rabbitMessagingTemplate.convertAndSend(RabbitKeys.BASE_EXCHANGE_NAME, key, resultMsg);
    }

    @Autowired
    public void setObjectMapper(ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
    }

    @Autowired
    public void setMessagingTemplate(RabbitMessagingTemplate messagingTemplate) {
        this.messagingTemplate = messagingTemplate;
    }

    @Autowired
    public void setStringRedisTemplate(ReactiveStringRedisTemplate stringRedisTemplate) {
        this.stringRedisTemplate = stringRedisTemplate;
    }

    @Autowired
    public void setReactiveRedisTemplate(ReactiveRedisTemplate<String, Object> redisTemplate) {
        this.reactiveRedisTemplate = redisTemplate;
    }

    @Autowired
    public void setCwWebClient(CwWebClient wiseClient) {
        this.cwWebClient = wiseClient;
    }

    @Autowired
    public void setRabbitMessagingTemplate(RabbitMessagingTemplate rabbitMessagingTemplate) {
        this.rabbitMessagingTemplate = rabbitMessagingTemplate;
    }
}
